package com.fins.gt.server;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javassist.expr.NewArray;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fins.gt.common.Const;
import com.fins.gt.export.AbstractXlsWriter;
import com.fins.gt.export.SimpleXlsWriter;
import com.fins.gt.model.ColumnInfo;
import com.fins.gt.model.FilterInfo;
import com.fins.gt.model.GridInfo;
import com.fins.gt.model.PageInfo;
import com.fins.gt.model.SortInfo;
import com.fins.gt.util.BeanUtils;
import com.fins.gt.util.BytesUtils;

import com.fins.gt.util.ModelUtils;
import com.fins.gt.util.StringUtils;


/**
 * @author fins
 * 
 */
public class GridServerHandler {
	
	private static Logger logger = LoggerFactory.getLogger(GridServerHandler.class);
	

	public static String CONTENTTYPE = "text/html; charset=UTF-8";
	public static String GT_JSON_NAME = "_gt_json";
	public static String DATA_ROOT = "data";
		
		private String action;
		private String exception;

		private List data;
		private String recordType;
		private String encoding=null;
		private boolean encodeFileName = true ;
		
		private List fieldsName;
		
		private boolean success;
		
		private HttpServletRequest request;
		private HttpServletResponse response;

		//private JSONObject jsonObject;
		
		private Class dataBeanClass=null;
		//private JSONArray jsonData =null;
		private String jsonData;
		private GridInfo gridInfo = new GridInfo();
		
		private PageInfo pageInfo = new PageInfo();
		
		private List sortInfo = new ArrayList();
		private List filterInfo= new ArrayList();
		private List columnInfo= new ArrayList();
		
		private Map parameters = new HashMap();
		
		private Map parameterMap;
		
		private Map writers = new HashMap();
		//输出数据进行封装的map
		private Map outdata = new HashMap();
		
		private JsonNode parametersJsonNode;
		
		public JsonNode getParametersJsonNode() {
			return parametersJsonNode;
		}

		public void setParametersJsonNode(JsonNode parametersJsonNode) {
			this.parametersJsonNode = parametersJsonNode;
		}

		private JsonNode rootNode;
		
		public JsonNode getRootNode() {
			return rootNode;
		}

		public void setRootNode(JsonNode rootNode) {
			this.rootNode = rootNode;
		}

		public GridServerHandler(){}
		
		public GridServerHandler(String gtJson){
			init(gtJson);
		}
		
		public GridServerHandler(Map parameterMap){
			setParameterMap(parameterMap);
			logger.info("init进行初始化。。。。");
			init();
		}
		
		public GridServerHandler(HttpServletRequest request,HttpServletResponse response) {
			logger.info("gt-grid 入口---");
			setRequest(request);
			setResponse(response);
			init();
		}

		public void init(String gtJson) {
			logger.info("AJAX IN : "+ gtJson);
			if (StringUtils.isNotEmpty(gtJson)){
				//try {
					logger.info(" AJAX IN : "+gtJson);
					ObjectMapper mapper = new ObjectMapper();
					//SerializationConfig sc = mapper.getSerializationConfig();
		            try {
		            	rootNode = mapper.readValue(gtJson, JsonNode.class);
		            	logger.info("rootNode--- "+rootNode);
		            	JsonNode actionJsonNode = rootNode.get("action");
		            	String action = actionJsonNode.getTextValue();
		            	logger.info("action--- "+action);
		            	
		            	JsonNode parametersJsonNode = rootNode.get("parameters");
		            	this.setParametersJsonNode(parametersJsonNode);
						logger.info(" parametersJsonNode : "+parametersJsonNode);
						//parameters.put("parametersJsonNode", parametersJsonNode);
		            	/*JsonNode recordTypeJsonNode = rootNode.get("recordType");
		            	String recordType = recordTypeJsonNode.getTextValue();
						logger.info("recordType :::"+recordTypeJsonNode.getTextValue());
						
						JsonNode parametersJsonNode = rootNode.get("parameters");
						logger.info(" parametersJsonNode : "+parametersJsonNode);
						
						JsonNode gridInfoJsonNode = rootNode.get("gridInfo");
						logger.info("gridInfoJsonNode-- "+gridInfoJsonNode);

						JsonNode pageInfoJsonNode = rootNode.get("pageInfo");
						logger.info("pageInfoJsonNode-- "+pageInfoJsonNode);
						
						JsonNode sortInfoJsonNode = rootNode.get("sortInfo");
						logger.info("sortInfoJsonNode=-- "+sortInfoJsonNode);
						
						JsonNode filterInfoJsonNode = rootNode.get("filterInfo");
						logger.info("filterInfoJsonNode-- "+filterInfoJsonNode);
		            	
		            	JsonNode columnInfoJsonNode = rootNode.get("columnInfo");
		            	logger.info("***  columnInfoJsonNode=-- "+columnInfoJsonNode);
		            	*/
						initGridInfo();
						
						if ("load".equalsIgnoreCase(action)){
							initPageInfo();
							initSortInfo();
							initFilterInfo();
						}else if ("save".equalsIgnoreCase(action)){
							
						}else if ("export".equalsIgnoreCase(action)){
							initColumnInfo();
						}
					} catch (JsonParseException e) {
						e.printStackTrace();
					} catch (JsonMappingException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
		         
			}
		}
		
		public void init() {
			logger.info("init................ ");
			//logger.info("GT_JSON_NAME................ "+GT_JSON_NAME);
			//logger.info("getParameter---"+getParameter(GT_JSON_NAME));
			init(getParameter(GT_JSON_NAME));
		}
		
		public void initGridInfo(){
			JsonNode gridInfoJsonNode = rootNode.get("gridInfo");
			logger.info("gridInfoJsonNode-- "+gridInfoJsonNode);
			if (gridInfoJsonNode!=null) {
				setGridInfo(ModelUtils.createGridInfo(gridInfoJsonNode));
			}
		}
		
		public void initPageInfo(){
			JsonNode pageInfoJsonNode = rootNode.get("pageInfo");
			logger.info("pageInfoJsonNode-- "+pageInfoJsonNode);
			if (pageInfo!=null){
				setPageInfo(ModelUtils.createPageInfo(pageInfoJsonNode));
			}
		}
		
		public void initSortInfo(){
			JsonNode sortInfoJsonNode = rootNode.get("sortInfo");
			logger.info("sortInfoJsonNode=-- "+sortInfoJsonNode);
			Iterator<JsonNode> nodes = sortInfoJsonNode.getElements(); 
			while (nodes.hasNext()) {  
	            JsonNode node = nodes.next();  
	            sortInfo.add( ModelUtils.createSortInfo(node));  
	        }  
		}
		
		public void initFilterInfo(){
			JsonNode filterInfoJsonNode = rootNode.get("filterInfo");
			logger.info("filterInfoJsonNode=-- "+filterInfoJsonNode);
			Iterator<JsonNode> nodes = filterInfoJsonNode.getElements(); 
			while (nodes.hasNext()) {  
	            JsonNode node = nodes.next();
	            logger.info("initFilterInfo-----  "+node);
	            sortInfo.add( ModelUtils.createFilterInfo(node));  
	        }  
		}
		
		public void initColumnInfo(){
			JsonNode columnInfoJsonNode = rootNode.get("columnInfo");
			logger.info("columnInfoJsonNode=-- "+columnInfoJsonNode);
			Iterator<JsonNode> nodes = columnInfoJsonNode.getElements(); 
			while (nodes.hasNext()) {  
	            JsonNode node = nodes.next();  
	            columnInfo.add(ModelUtils.createColumnInfo(node)); 
	        }  
		}
		

		public void setXlsWriter(AbstractXlsWriter writer){
			writers.put("xls", writer);
		}
		
		public AbstractXlsWriter getXlsWriter(){
			AbstractXlsWriter writer=null;
			try {
			 writer = (AbstractXlsWriter)writers.get("xls");
			} catch (Exception e) {
				logger.info("严重异常--- "+e);
			} 
			if (writer==null){
				writer=new SimpleXlsWriter();
			}
			return writer;
		}
		
		public List getDisplayColumnInfo(){
			List disColumnInfo = new ArrayList();
			if (columnInfo!=null){
				for (int i=0,len=columnInfo.size();i<len;i++) {
					ColumnInfo col=(ColumnInfo)columnInfo.get(i);
					if (!col.isHidden()) {
						disColumnInfo.add(col);
					}
				}
			}
			return disColumnInfo;
		}
		
		public String getSaveResponseText(){
			ObjectMapper mapper = new ObjectMapper();
			
			StringWriter sw = new StringWriter();  
			JsonGenerator gen;
			try {
				gen = new JsonFactory().createJsonGenerator(sw);
				outdata.put("success", success);
				outdata.put("exception", exception);
				mapper.writeValue(gen, outdata); 
				gen.close();
				
			} catch (IOException e) {
				e.printStackTrace();
			}  
			this.setException(exception);
			this.setSuccess(success);
			logger.info("getSaveResponseText sw-- "+sw.toString());
			return sw.toString();
		}
		//JSONObject
		public String getLoadResponseJSON(){
			ObjectMapper mapper = new ObjectMapper();
			StringWriter sw = new StringWriter();  
			JsonGenerator gen;
			try {
				//怎样把多个对象联合起来进行输出就可以了。
				outdata.put("pageInfo", getPageInfo());
				outdata.put("data", data);
				outdata.put("exception", exception);
				gen = new JsonFactory().createJsonGenerator(sw);
				mapper.writeValue(gen, outdata); 
				gen.close();
				
			} catch (IOException e) {
				e.printStackTrace();
			}  
			// "pageInfo":{"totalRowNum":2},
		    //"data":
			//String finalInfo = "{\"pageInfo\":{\"totalRowNum\":2},"+"\"data\": "+sw.toString()+"}";  
			logger.info("getLoadResponseJSON--- 数据 :::"+sw.toString() ); 
			return sw.toString();
		}
		
		public String getLoadResponseText(){
			String json = getLoadResponseJSON();//还要进行转换为json string
			String jstr=json==null?"":json.toString();
			logger.info(" AJAX OUT : "+jstr);
			return jstr;
		}
		
		//新的实现方法，使用jackson进行实现.
		public void setData(List data) {
			this.data = data;
			this.dataBeanClass=null;
			logger.info("setData List data::::::::: "+data);
			ObjectMapper mapper = new ObjectMapper();
			StringWriter sw = new StringWriter();  
			JsonGenerator gen;
			try {
				outdata.put("data", data);
				gen = new JsonFactory().createJsonGenerator(sw);
				mapper.writeValue(gen, outdata); 
				gen.close();
			} catch (IOException e) {
				e.printStackTrace();
			}  
			
			String finalInfo = sw.toString();  
			logger.info("setData 数据 is:"+finalInfo ); 
			setJsonData(finalInfo);//(jsonConvert.modelCollect2JSONArray(data));
		}
		//有关联表的使用这个方法
		/*public void setData(List data, Collection jsonAwareCollect) {
			logger.info("setData-----1----- ");
			this.data = data;
			this.dataBeanClass=null;
			logger.info("setData------List data::::::::: "+data);
		}*/
		
		//这个方法可以不需要
		/*public void setData(List data,Class beanClass) {
			logger.info("setData----2-----");
			this.data = data;
			this.dataBeanClass=beanClass;
			ObjectMapper mapper = new ObjectMapper();
			StringWriter sw = new StringWriter();  
			JsonGenerator gen;
			try {
				gen = new JsonFactory().createJsonGenerator(sw);
				outdata.put("data", data);
				mapper.writeValue(gen, outdata);  
				gen.close();  
			} catch (IOException e) {
				e.printStackTrace();
			}  
			String finalInfo = sw.toString();  
			logger.info("转换的finalinfo is:"+finalInfo );  
			setJsonData(finalInfo);
		}*/
		
		//模板调用
		/*public void setDataModel(List data,Class beanClass) {
			logger.info("setDataModel---------");
			this.data = data;
			this.dataBeanClass=beanClass;
			ObjectMapper mapper = new ObjectMapper();
			StringWriter sw = new StringWriter();  
			JsonGenerator gen;
			try {
				gen = new JsonFactory().createJsonGenerator(sw);
				mapper.writeValue(gen, data);  
				gen.close();  
			} catch (IOException e) {
				e.printStackTrace();
			}  
			String finalInfo = sw.toString();  
			logger.info("转换的finalinfo is:"+finalInfo );  
			setJsonData(finalInfo);
		}*/
		
		
		/**
		public List getUpdatedRecords() {
			return getRecordsList("updatedRecords");
		}
		
		public List getUpdatedRecords(Class beanClass) {
			return getRecordsList("updatedRecords",beanClass);
		}*/
		//add
		public JsonNode getInsertedJsonNodeRecords() {
			return getJsonNodeRecordsList("insertedRecords");
		}
		public JsonNode getUpdatedJsonNodeRecords() {
			return getJsonNodeRecordsList("updatedRecords");
		}
		public JsonNode getDeletedJsonNodeRecords() {
			return getJsonNodeRecordsList("deletedRecords");
		}
		
		//下面三个方法重新写
		/*public List getNewInsertedRecords(Class beanClass) {
			return getNewRecordsList("insertedRecords",beanClass);
		}	
		
		public List getNewUpdatedRecords(Class beanClass) {
			return getNewRecordsList("updatedRecords",beanClass);
		}
		
		public List getNewDeletedRecords(Class beanClass) {
			return getNewRecordsList("deletedRecords",beanClass);
		}*/
		//选择列的获取
		/*public List getNewSelectedRecords(Class beanClass){
			return getNewRecordsList("selectedRecords",beanClass);
		}
		
		
		public List getRecordsList(String rname,Class beanClass) {
			logger.info("getRecordsList------rname--- "+rname+"  beaClass---- "+beanClass);
			List<Object> recordsList = null;
			return recordsList;
		}
		
		public List getNewRecordsList(String name,Class beanClass){
			logger.info("getNewRecordsList-- ");
			List recordsList = new ArrayList();
			return recordsList;
		}*/
		
		
		// new 
		public JsonNode getJsonNodeRecordsList(String rname) {
			logger.info("getJsonNodeRecordsList------rname--- "+rname);
			JsonNode recordsJsonNode = rootNode.get(rname);
			return recordsJsonNode;
		}
		//获取转换为map
		/*public List getRecordsList(String rname) {
			logger.info("getRecordsList------rname--- "+rname);
			JsonNode recordsJsonNode = rootNode.get(rname);
			System.out.println("recordsList--- "+recordsJsonNode);
			Iterator<JsonNode> nodes = recordsJsonNode.getElements(); 
			while (nodes.hasNext()) {  
	            JsonNode node = nodes.next();  
	            logger.info("循环获取值:: "+node.toString());
	            columnInfo.add(ModelUtils.createColumnInfo(node)); 
	        } 
			List recordsList = new ArrayList();
			
			return recordsList;
		}*/
		
		public String[] getParameterValues(String name){
			return (String[])parameterMap.get(name);
		}
		public String getParameter(String name){
			String[] pv=getParameterValues(name);
			if (pv!=null && pv.length>0){
				return pv[0];
			}
			return null;
		}
		
		/*public void printResponseText(String text){
			try {
				response.setContentType(CONTENTTYPE);
				PrintWriter out = response.getWriter();
				out.println(text);
				out.flush();
				out.close();
			} catch (IOException e) {
				logger.error(" 严重错误，printResponse ");
			}	
		}*/

		
		public void initAttachmentHeader(){
			getResponse().setHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0" );
			getResponse().setHeader("Content-Type","application/force-download" );
			getResponse().setHeader("Content-Type","application/octet-stream" );
			getResponse().setHeader("Content-Type","application/download" );
			getResponse().setHeader("Cache-Control","private, max-age=0, must-revalidate" );
			getResponse().setHeader("Pragma","public" );
		}
		
		public void downloadFile( String fileName){
			downloadFile(fileName,Const.nullInt);
		}
	

		public String encodeFileName(String fileName){
			String agent = getRequest().getHeader("USER-AGENT");
			fileName=fileName.replaceAll("\n|\r", " ").trim();
			if (null != agent){
				try {
					agent=agent.toUpperCase();
					if (agent.indexOf("MSIE")!=-1) {
						fileName = URLEncoder.encode(fileName, "UTF8");
					} else if (agent.indexOf("MOZILLA")!=-1) {
						fileName = "=?UTF-8?B?"+(new String(BytesUtils.toBase64Chars(fileName.getBytes("UTF-8"))))+"?=";
					} 
				} catch (UnsupportedEncodingException e) {
					// do nothing
				}
			}
			return fileName;
		}
		
		public void downloadFile( String fileName ,long  length){
			initAttachmentHeader();
			if (isEncodeFileName()){
				fileName=encodeFileName(fileName);
			}
			getResponse().setHeader("Content-Disposition","attachment; filename=\""+fileName+"\"");		
			if (length!=Const.nullInt){
				getResponse().setHeader("Content-Length",String.valueOf(length) );
			}
		}
		

		
		public void exportXLS(List data,Class beanClass) throws IOException{
			List cols = this.getDisplayColumnInfo();
			int len=cols.size();
			
			String[] properiesName=new String[len] ;
			String[] headsName=new String[len] ;
			for (int i=0;i<len;i++){
				ColumnInfo colInfo =(ColumnInfo)cols.get(i);
				properiesName[i]=colInfo.getFieldIndex();
				headsName[i]=colInfo.getHeader();				
			}

			exportXLS(data,properiesName,headsName,beanClass);
		}
		
		public void exportXLSfromMaps(List data) throws IOException{
			exportXLS(data, Map.class);
		}
		
		public void exportXLS(List data,String[] properiesName, String[] headsName, Class beanClass) throws IOException{
			String fileName="liangtest";//getParameter("exportFileName");
			downloadFile(fileName+".xls");
			
			OutputStream out=getResponse().getOutputStream();
			AbstractXlsWriter xlsw= getXlsWriter();
			xlsw.init();
			xlsw.setOut(out);
			xlsw.setEncoding(getEncoding());
			xlsw.start();
			xlsw.addRow( headsName );
			if (beanClass==null || Map.class.isAssignableFrom(beanClass) ){
				for (int i=0,len=data.size();i<len;i++){
					Map record=(Map)data.get(i);
					xlsw.addRow(BeanUtils.map2Array(record,properiesName));
				}
			}else{
				for (int i=0,len=data.size();i<len;i++){
					Object record= data.get(i);
					xlsw.addRow( BeanUtils.bean2Array(record,properiesName,beanClass) );
				}
			}
			
			xlsw.end();		
			xlsw.close();
		}
		
		public void exportXLSfromMaps(List data,String[] properiesName, String[] headsName) throws IOException{
			exportXLS(data, properiesName, headsName, Map.class);
		}
		
		
		/*public void printSaveResponseText(){
			printResponseText(getSaveResponseText());
		}
		
		public void printLoadResponseText(){
			printResponseText(getLoadResponseText());
		}*/
		
		public String getAction() {
			return action;
		}

		public void setAction(String action) {
			this.action = action;
		}

	
		public Map getParameters() {
			return parameters;
		}

		public void setParameters(Map parameters) {
			this.parameters = parameters;
		}

		public String getException() {
			return exception;
		}

		public void setException(String exception) {
			this.exception = exception;
		}

		
		public List getSortInfo() {
			return sortInfo;
		}

		public void setSortInfo(List sortInfo) {
			this.sortInfo = sortInfo;
		}
		public SortInfo getSingleSortInfo(){
			return sortInfo==null||sortInfo.size()<1?null:(SortInfo)sortInfo.get(0);
		}
		public List getFilterInfo() {
			return filterInfo;
		}

		public void setFilterInfo(List filterInfo) {
			this.filterInfo = filterInfo;
		}
		public FilterInfo getSingleFilterInfo(){
			return filterInfo==null||filterInfo.size()<1?null:(FilterInfo)filterInfo.get(0);
		}
		public List getData() {
			return data;
		}

		public String getRecordType() {
			return recordType;
		}

		public void setRecordType(String recordType) {
			this.recordType = recordType;
		}

		public List getFieldsName() {
			return fieldsName;
		}

		public void setFieldsName(List fieldsName) {
			this.fieldsName = fieldsName;
		}

		public boolean isSuccess() {
			return success;
		}

		public void setSuccess(boolean success) {
			this.success = success;
		}

		public int getPageSize() {
			return getPageInfo().getPageSize();
		}

		public void setPageSize(int pageSize) {
			getPageInfo().setPageSize(pageSize);
		}

		public int getPageNum() {
			return getPageInfo().getPageNum();

		}

		public void setPageNum(int pageNum) {
			getPageInfo().setPageNum(pageNum );
		}

		public int getTotalRowNum() {
			return  getPageInfo().getTotalRowNum();
		}

		public void setTotalRowNum(int totalRowNum) {
			getPageInfo().setTotalRowNum(totalRowNum) ;
		}

		public int getTotalPageNum() {
			return getPageInfo().getTotalPageNum();
		}

		public void setTotalPageNum(int totalPageNum) {
			getPageInfo().setTotalPageNum(totalPageNum);
		}

		public int getStartRowNum() {
			return getPageInfo().getStartRowNum();
		}

		public void setStartRowNum(int startRowNum) {
			getPageInfo().setStartRowNum(startRowNum );
		}

		public int getEndRowNum() {
			return getPageInfo().getEndRowNum();
		}

		public void setEndRowNum(int endRowNum) {
			getPageInfo().setEndRowNum(endRowNum );
		}

		public HttpServletRequest getRequest() {
			return request;
		}

		public void setRequest(HttpServletRequest request) {
			this.request = request;
			setParameterMap(request.getParameterMap());
		}

		public HttpServletResponse getResponse() {
			return response;
		}

		public void setResponse(HttpServletResponse response) {
			this.response = response;
		}

		public Class getDataBeanClass() {
			return dataBeanClass;
		}
		public void setDataBeanClass(Class dataBeanClass) {
			this.dataBeanClass = dataBeanClass;
		}

		public Map getParameterMap() {
			return parameterMap;
		}

		public void setParameterMap(Map parameterMap) {
			this.parameterMap = parameterMap;
		}
		public static int getInt(Object i){
			return getInt(i,-1);
		}
		public static int getInt(Object i,int defaultI){
			try {
				if (i!=null){
					return Integer.parseInt(String.valueOf(i));
				}
			} catch (Exception e) {	}
			return defaultI;
		}

		public PageInfo getPageInfo() {
			return pageInfo;
		}

		public void setPageInfo(PageInfo pageInfo) {
			this.pageInfo = pageInfo;
		}

		public GridInfo getGridInfo() {
			return gridInfo;
		}

		public void setGridInfo(GridInfo gridInfo) {
			this.gridInfo = gridInfo;
		}

		public String getEncoding() {
			return encoding;
		}

		public void setEncoding(String encoding) {
			this.encoding = encoding;
		}

		public List getColumnInfo() {
			return columnInfo;
		}

		public void setColumnInfo(List columnInfo) {
			this.columnInfo = columnInfo;
		}

		public boolean isEncodeFileName() {
			return encodeFileName;
		}

		public void setEncodeFileName(boolean encodeFileName) {
			this.encodeFileName = encodeFileName;
		}

		public String getJsonData() {
			return jsonData;
		}

		public void setJsonData(String jsonData) {
			this.jsonData = jsonData;
		}

}